package net.sf.calibur.transport;

import net.sf.calibur.transport.message.CommandMessage;
import net.sf.calibur.transport.message.HeartBeatMessage;
import net.sf.calibur.transport.message.Message;
import net.sf.calibur.transport.message.RequestSessionMessage;
import net.sf.calibur.transport.message.SessionEstablishedMessage;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public enum SessionState implements SessionOperation {
	CONNECTED {
		@Override
		public void connected(Session session) {
			SessionEstablishedMessage message = new SessionEstablishedMessage();
			message.setEstablishTimestamp(session.getEstablishTimestamp());
			message.setSessionKey(session.getKey());
			session.sendMessage(message);
		}

		@Override
		public void messageReceived(Session session, Message message) {
			if (message.getType() != Message.MT_REQUEST_SESSION) {
				throw new IllegalStateException(String.format(
						"Session state [%s] received unknown message type %d.",
						name(), message.getType()));
			}

			RequestSessionMessage rsm = (RequestSessionMessage) message;
			session.setRequestTimestamp(rsm.getRequestTimestamp());
			session.setState(SessionState.ESTABLISHED);
		}

		@Override
		public void exceptionCaught(Session session, Throwable cause) {
			logger.error(String
					.format("Session Key:%s State:%s caught exception, session closed.",
							session.getKey(), name()), cause);
			session.close();
		}

		@Override
		public void idle(Session session) {
			logger.info(String
					.format("Session Key:%s State:%s caught exception, session closed.",
							session.getKey(), name()));
			session.close();
		}
	},

	ESTABLISHED {
		@Override
		public void idle(Session session) {
			logger.info("Checking heartbeat ...");
			if (session.isCheckingHeartBeat()) { // 已经开始检测heartbeat
				logger.error("Session closed by lost heartbeat.");
				session.getSessionManager().sessionLost(session, null);
				session.close();
			} else { // 发送heartbeat报文
				session.setCheckingHeartbeat(true);
				HeartBeatMessage hbm = new HeartBeatMessage(
						Message.MT_SERVER_HEARTBEAT);
				session.sendMessage(hbm);
			}
		}

		@Override
		public void exceptionCaught(Session session, Throwable cause) {
			if (logger.isInfoEnabled()) {
				logger.info(String
						.format("Session Key:%s State:%s caught exception, session closed.",
								session.getKey(), name()), cause);
			}

			session.getSessionManager().sessionLost(session, cause);
			session.close();
		}

		@Override
		public void closed(Session session) {
			if (logger.isDebugEnabled()) {
				logger.debug(String.format("Session Key:%s State:%s closed.",
						session.getKey(), name()));
			}

			session.getSessionManager().sessionLost(session, null);
			session.close();
		}

		@Override
		public void messageReceived(Session session, Message message) {
			switch (message.getType()) {
			case Message.MT_APPLICATION: // 应用报文
				// 发送指令收妥消息给客户端
				session.sendMessage(commandAck);
				// 向CaliburEngine产生CommandEvent事件
				CommandMessage cm = (CommandMessage) message;
				session.getSessionManager().onCommandMessage(session, cm);
				break;

			case Message.MT_CLIENT_HEARTBEAT: // 客户端主动检测心跳
				HeartBeatMessage hbm = new HeartBeatMessage(
						Message.MT_CLIENT_HEARTBEAT_ACK);
				session.sendMessage(hbm);
				break;

			case Message.MT_SERVER_HEARTBEAT_ACK: // 服务器主动检测心跳的响应
				session.setCheckingHeartbeat(false);
				break;

			default: // 接收到不希望的消息类型
				throw new IllegalStateException(String.format(
						"Session state [%s] received unknown message type %d.",
						name(), message.getType()));
			}
		}
	},

	CLOSED {
		@Override
		public void connected(Session session) {
			throw new IllegalStateException();
		}

		@Override
		public void messageReceived(Session session, Message message) {
			throw new IllegalStateException();
		}

		@Override
		public void closed(Session session) {
			throw new IllegalStateException();
		}
	};

	private static Logger logger = LoggerFactory.getLogger(SessionState.class);
	private static Message commandAck = Message.createMessage(
			Message.MT_APPLICATION_ACK, null);

	@Override
	public void connected(Session session) {
		throw new IllegalStateException();
	}

	@Override
	public void exceptionCaught(Session session, Throwable cause) {
		logger.error(String
				.format("Session Key:%s State:%s caught exception, session closed.",
						session.getKey(), name()), cause);
		session.close();
	}

	@Override
	public void messageReceived(Session session, Message message) {
		throw new IllegalStateException();
	}

	@Override
	public void closed(Session session) {
		session.close();
	}

	@Override
	public void idle(Session session) {
		// throw new IllegalStateException();
	}
}
